# -*- coding: utf-8 -*-
#
# Copyright 2009 Vanderbilt University
# 
# Licensed under the Apache License, Version 2.0 (the "License"); 
# you may not use this file except in compliance with the License. 
# You may obtain a copy of the License at 
# 
#     http://www.apache.org/licenses/LICENSE-2.0 
# 
# Unless required by applicable law or agreed to in writing, software 
# distributed under the License is distributed on an "AS IS" BASIS, 
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
# See the License for the specific language governing permissions and 
# limitations under the License. 

"""

.. moduleauthor:: John Paulett <john.paulett -at- vanderbilt.edu>
"""

from hornet.event import GraphsReady
from hornet.file import write_csv
from hornet.plot import loglog
from hornet.plugin import Plugin, log
from hornet.util import count_unique
import logging

logger = logging.getLogger(__name__)

#TODO: remove the source (just use the graph's name)
class AbstractDistribution(Plugin):
    """Base class for characterizing the distribution of something.
    Specific implementations indication what that something is. This base 
    class contains the algorithms for transforming and presenting the data.
    Implementations must override several methods to be valid.
    """
    @log
    def notify(self, event):
        for graph in event.data:
            self._analyze(event.caller, graph)
    
    def accepted_events(self):
        return GraphsReady
    
    def _analyze(self, source, graph):
        # loop over all the nodes and use the implementation-specific
        # result of _get_value for that node.
        sizes = [self._get_value(graph, node) for node in graph.nodes_iter()]
        name = graph.name
        # we then create a dictionary unique values and the number occurrences
        # of that unique value
        results = count_unique(sizes)
        # output the results
        self._output_table(source, name, results)
        self._output_plot(source, name, results)
        
    def _output_table(self, source, name, results):
        """Display the raw data"""
        write_csv(self._filename(source, name, 'csv'), 
                  results.items(),
                  header=[self._get_independent_label(), 
                          self._get_dependent_label()])
    
    def _output_plot(self, source, name, results):
        """Create log, log distribution plot"""
        loglog(results.keys(), results.values(), '.', 
               xlabel=self._get_independent_label(), 
               ylabel=self._get_dependent_label(), 
               title='%s - %s' % (source, name), 
               filename=self._filename(source, name, 'png'))

    def _filename(self, source, name, extension):
        return self.output(self._filename_template() % (source, name, extension))
    
    def _filename_template(self):
        """Should be overridden to provide the filename that results
        should be saved to.  Should allow for a string interpolation
        for three values. Should not include the path to the file.
        """
        raise NotImplementedError()
    
    def _get_value(self, graph, node):
        """Should be overridden to return the the count needed."""
        raise NotImplementedError()

    def _get_independent_label(self):
        """Should be overridden to return the independent (x value of the plot)
        label.
        """
        raise NotImplementedError()
    
    def _get_dependent_label(self):
        """Should be overridden to return the dependent (i value of the plot)
        label.
        """
        raise NotImplementedError()
            
class EdgesPerNodeDistribution(AbstractDistribution):
    """Calculates the distribution of edges per node."""
    def _filename_template(self):
        return 'edges_per_node_%s_%s.%s'
    
    def _get_value(self, graph, node):
        return len(graph[node])

    def _get_independent_label(self):
        return 'Number of Edges'
    
    def _get_dependent_label(self):
        return 'Number of Nodes'
    
class AttributesPerNodeDistribution(AbstractDistribution):
    """Calculates the distribution of attributes per node."""
    def _filename_template(self):
        return 'attributes_per_node_%s_%s.%s'
    
    def _get_value(self, graph, node):
        return node.size
    
    def _get_independent_label(self):
        return 'Number of Attributes'
    
    def _get_dependent_label(self):
        return 'Number of Nodes'
    